#include "ScriptHelpers.h"

#include "Game/Game.h"
#include "Game/Entity.h"
#include "Game/WarEntity.h"

namespace Binds
{
	static int Bind_Entity(lua_State *L);
	static int Bind_WarEntity(lua_State *L);
	
	static int Bind_Game_pollEvents(lua_State *L)
	{
		const bool result = Game::pollEvents();
		lua_pushboolean(L, result);
		return 1;
	}
	
	static const luaL_Reg Game_Methods[] = {
		{"pollEvents", Bind_Game_pollEvents},
		{NULL, NULL}
	};
	
	int bindGame(lua_State *L)
	{
		script_bind_methods(L, "Game", Game_Methods);
		
		Bind_Entity(L);
		Bind_WarEntity(L);
		
		return 0;
	}
	
	static int Bind_Entity_new(lua_State *L)
	{
		Entity *obj = script_new(L, Entity);
		//ASSERT(obj);
		
		return 1;
	}
	
	int Bind_Entity_getAngle(lua_State *L)
	{
		if (const Entity *obj = script_cast<Entity*>(L, 1))
		{
			const vec3 angle = obj->getAngle();
			lua_pushnumber(L, angle.x);
			lua_pushnumber(L, angle.y);
			lua_pushnumber(L, angle.z);
			return 3;
		}
		
		return 0;
	}
	
	int Bind_Entity_setAngle(lua_State *L)
	{
		if (Entity *obj = script_cast<Entity*>(L, 1))
		{
			obj->setAngle(vec3(
				lua_isnumber(L, 2) ? lua_tonumber(L, 2) : 0.0f,
				lua_isnumber(L, 3) ? lua_tonumber(L, 3) : 0.0f,
				lua_isnumber(L, 4) ? lua_tonumber(L, 4) : 0.0f
			));
		}
		
		return 0;
	}
	
	int Bind_Entity_getPosition(lua_State *L)
	{
		if (const Entity *obj = script_cast<Entity*>(L, 1))
		{
			const vec3 pos = obj->getPosition();
			lua_pushnumber(L, pos.x);
			lua_pushnumber(L, pos.y);
			lua_pushnumber(L, pos.z);
			return 3;
		}
		
		return 0;
	}
	
	int Bind_Entity_setPosition(lua_State *L)
	{
		if (Entity *obj = script_cast<Entity*>(L, 1))
		{
			obj->setPosition(vec3(
				lua_isnumber(L, 2) ? lua_tonumber(L, 2) : 0.0f,
				lua_isnumber(L, 3) ? lua_tonumber(L, 3) : 0.0f,
				lua_isnumber(L, 4) ? lua_tonumber(L, 4) : 0.0f
			));
		}
		
		return 0;
	}
	
	int Bind_Entity_getHitbox(lua_State *L)
	{
		if (const Entity *obj = script_cast<Entity*>(L, 1))
		{
			const Hitbox hitbox = obj->getHitbox();
			lua_pushnumber(L, hitbox.x);
			lua_pushnumber(L, hitbox.y);
			lua_pushnumber(L, hitbox.w);
			lua_pushnumber(L, hitbox.h);
			return 4;
		}
		
		return 0;
	}
	
	int Bind_Entity_setHitbox(lua_State *L)
	{
		if (Entity *obj = script_cast<Entity*>(L, 1))
		{
			obj->setHitbox(Hitbox(
				lua_isnumber(L, 2) ? lua_tonumber(L, 2) : 0.0f,
				lua_isnumber(L, 3) ? lua_tonumber(L, 3) : 0.0f,
				lua_isnumber(L, 4) ? lua_tonumber(L, 4) : 0.0f,
				lua_isnumber(L, 5) ? lua_tonumber(L, 5) : 0.0f
			));
		}
		
		return 0;
	}
	
	int Bind_Entity_isCollide(lua_State *L)
	{
		if (Entity *obj = script_cast<Entity*>(L, 1))
		{
			lua_pushboolean(L, obj->isCollide(script_cast<Entity*>(L, 2)));
			return 1;
		}
		
		return 0;
	}
	
	int Bind_Entity_setTexture(lua_State *L)
	{
		if (Entity *obj = script_cast<Entity*>(L, 1))
			obj->setTexture(script_cast<Render::Texture*>(L, 2));
		
		return 0;
	}
	
	int Bind_Entity_setModel(lua_State *L)
	{
		if (Entity *obj = script_cast<Entity*>(L, 1))
			obj->setModel(script_cast<Render::Model*>(L, 2));
		
		return 0;
	}
	
	static const luaL_Reg Entity_Methods[] = {
		{"new",         Bind_Entity_new},
		{"__gc",        script_gc<Entity>},
		{"getAngle",    Bind_Entity_getAngle},
		{"setAngle",    Bind_Entity_setAngle},
		{"getPosition", Bind_Entity_getPosition},
		{"setPosition", Bind_Entity_setPosition},
		{"getHitbox",   Bind_Entity_getHitbox},
		{"setHitbox",   Bind_Entity_setHitbox},
		{"isCollide",   Bind_Entity_isCollide},
		{"setTexture",  Bind_Entity_setTexture},
		{"setModel",    Bind_Entity_setModel},
		{NULL, NULL}
	};
	
	static int Bind_Entity(lua_State *L)
	{
		script_bind_methods(L, "Entity", Entity_Methods);
		return 0;
	}
	
	static int Bind_WarEntity_new(lua_State *L)
	{
		WarEntity *obj = script_new(L, WarEntity);
		//ASSERT(obj);
		
		return 1;
	}
	
	int Bind_WarEntity_isFiring(lua_State *L)
	{
		if (const WarEntity *obj = script_cast<WarEntity*>(L, 1))
		{
			lua_pushboolean(L, obj->isFiring());
			return 1;
		}
		
		return 0;
	}
	
	int Bind_WarEntity_setFiring(lua_State *L)
	{
		if (WarEntity *obj = script_cast<WarEntity*>(L, 1))
		{
			if (lua_isboolean(L, 2))
				obj->setFiring(lua_toboolean(L, 2));
		}
		
		return 0;
	}
	
	int Bind_WarEntity_setTarget(lua_State *L)
	{
		if (WarEntity *obj = script_cast<WarEntity*>(L, 1))
			obj->setTarget(script_cast<Entity*>(L, 2));
		
		return 0;
	}
	
	static const luaL_Reg WarEntity_Methods[] = {
		{"new",       Bind_WarEntity_new},
		{"__gc",      script_gc<WarEntity>},
		{"isFiring",  Bind_WarEntity_isFiring},
		{"setFiring", Bind_WarEntity_setFiring},
		{"setTarget", Bind_WarEntity_setTarget},
		{NULL, NULL}
	};
	
	static int Bind_WarEntity(lua_State *L)
	{
		script_bind_methods(L, "WarEntity", Entity_Methods);
		script_bind_methods(L, "WarEntity", WarEntity_Methods);
		return 0;
	}
}
